home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / osrc.arc / MBUF.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-03-20  |  8.6 KB  |  431 lines

  1. /* Primitive mbuf allocate/free routines */
  2.  
  3. #include <stdio.h>
  4. #include "global.h"
  5. #include "mbuf.h"
  6.  
  7. /* Allocate mbuf with associated buffer of 'size' bytes */
  8. struct mbuf *
  9. alloc_mbuf(size)
  10. register int16 size;
  11. {
  12.     register struct mbuf *bp;
  13.  
  14.     if((bp = (struct mbuf *)malloc((unsigned)(size + sizeof(struct mbuf)))) == NULLBUF)
  15.         return NULLBUF;
  16.  
  17.     bp->next = bp->anext = NULLBUF;
  18.     if(size != 0){
  19.         bp->data = (char *)(bp + 1);
  20.     } else {
  21.         bp->data = NULLCHAR;
  22.     }
  23.     bp->refcnt = 1;
  24.     bp->dup = NULLBUF;
  25.     bp->size = size;
  26.     bp->cnt = 0;
  27.     return bp;
  28. }
  29.  
  30. /* Decrement the reference pointer in an mbuf. If it goes to zero,
  31.  * free all resources associated with mbuf.
  32.  * Return pointer to next mbuf in packet chain
  33.  */
  34. struct mbuf *
  35. free_mbuf(bp)
  36. register struct mbuf *bp;
  37. {
  38.     register struct mbuf *bp1 = NULLBUF;
  39.  
  40.     if(bp != NULLBUF){
  41.         bp1 = bp->next;
  42.         if(--bp->refcnt == 0){
  43.             /* Follow indirection chain if necessary */
  44.             if(bp->dup != NULLBUF)
  45.                 free_mbuf(bp->dup);
  46.             free((char *)bp);
  47.         }
  48.     }
  49.     return bp1;
  50. }
  51.  
  52. /* Free packet (a chain of mbufs). Return pointer to next packet on queue,
  53.  * if any
  54.  */
  55. struct mbuf *
  56. free_p(bp)
  57. register struct mbuf *bp;
  58. {
  59.     register struct mbuf *abp;
  60.  
  61.     if(bp == NULLBUF)
  62.         return NULLBUF;
  63.     abp = bp->anext;
  64.     while(bp != NULLBUF)
  65.         bp = free_mbuf(bp);
  66.     return abp;
  67. }        
  68. /* Free entire queue of packets (of mbufs) */
  69. void
  70. free_q(q)
  71. struct mbuf **q;
  72. {
  73.     register struct mbuf *bp;
  74.  
  75.     while((bp = dequeue(q)) != NULLBUF)
  76.         free_p(bp);
  77. }
  78.  
  79. /* Count up the total number of bytes in an mbuf */
  80. int16
  81. len_mbuf(bp)
  82. register struct mbuf *bp;
  83. {
  84.     register int cnt = 0;
  85.  
  86.     while(bp != NULLBUF){
  87.         cnt += bp->cnt;
  88.         bp = bp->next;
  89.     }
  90.     return cnt;
  91. }
  92. /* Count up the number of packets in a queue */
  93. int16
  94. len_q(bp)
  95. register struct mbuf *bp;
  96. {
  97.     register int cnt;
  98.  
  99.     for(cnt=0;bp != NULLBUF;cnt++,bp = bp->anext)
  100.         ;
  101.     return cnt;
  102. }
  103. /* Trim mbuf to specified length by lopping off end */
  104. void
  105. trim_mbuf(bpp,length)
  106. struct mbuf **bpp;
  107. int16 length;
  108. {
  109.     register int16 tot = 0;
  110.     register struct mbuf *bp;
  111.  
  112.     if(bpp == NULLBUFP || *bpp == NULLBUF)
  113.         return;    /* Nothing to trim */
  114.  
  115.     if(length == 0){
  116.         /* Toss the whole thing */
  117.         free_p(*bpp);
  118.         *bpp = NULLBUF;
  119.         return;
  120.     }
  121.     /* Find the point at which to trim. If length is greater than
  122.      * the packet, we'll just fall through without doing anything
  123.      */
  124.     for( bp = *bpp; bp != NULLBUF; bp = bp->next){
  125.         if(tot + bp->cnt < length){
  126.             tot += bp->cnt;
  127.         } else {
  128.             /* Cut here */
  129.             bp->cnt = length - tot;
  130.             free_p(bp->next);
  131.             bp->next = NULLBUF;
  132.             break;
  133.         }
  134.     }
  135. }
  136. /* Duplicate/enqueue/dequeue operations based on mbufs */
  137.  
  138. /* Duplicate first 'cnt' bytes of packet starting at 'offset'.
  139.  * This is done without copying data; only the headers are duplicated,
  140.  * but without data segments of their own. The pointers are set up to
  141.  * share the data segments of the original copy. The return pointer is
  142.  * passed back through the first argument, and the return value is the
  143.  * number of bytes actually duplicated.
  144.  */
  145. int16
  146. dup_p(hp,bp,offset,cnt)
  147. struct mbuf **hp;
  148. register struct mbuf *bp;
  149. register int16 offset;
  150. register int16 cnt;
  151. {
  152.     register struct mbuf *cp;
  153.     int16 tot;
  154.  
  155.     if(cnt == 0 || bp == NULLBUF || hp == NULLBUFP){
  156.         if(hp != NULLBUFP)
  157.             *hp = NULLBUF;
  158.         return 0;
  159.     }
  160.     if((*hp = cp = alloc_mbuf(0)) == NULLBUF){
  161.         return 0;
  162.     }
  163.     /* Skip over leading mbufs that are smaller than the offset */
  164.     while(bp != NULLBUF && bp->cnt <= offset){
  165.         offset -= bp->cnt;
  166.         bp = bp->next;
  167.     }
  168.     if(bp == NULLBUF){
  169.         free_mbuf(cp);
  170.         *hp = NULLBUF;
  171.         return 0;    /* Offset was too big */
  172.     }
  173.     tot = 0;
  174.     for(;;){
  175.         /* Increment the duplicated buffer's reference count */
  176.         cp->dup = bp;
  177.         bp->refcnt++;
  178.  
  179.         cp->data = bp->data + offset;
  180.         cp->cnt = min(cnt,bp->cnt - offset);
  181.         offset = 0;
  182.         cnt -= cp->cnt;
  183.         tot += cp->cnt;
  184.         bp = bp->next;
  185.         if(cnt == 0 || bp == NULLBUF || (cp->next = alloc_mbuf(0)) == NULLBUF)
  186.             break;
  187.         cp = cp->next;
  188.     }
  189.     return tot;
  190. }
  191. /* Copy first 'cnt' bytes of packet into a new, single mbuf */
  192. struct mbuf *
  193. copy_p(bp,cnt)
  194. register struct mbuf *bp;
  195. register int16 cnt;
  196. {
  197.     register struct mbuf *cp;
  198.     register char *wp;
  199.     register int16 n;
  200.  
  201.     if(bp == NULLBUF || cnt == 0 || (cp = alloc_mbuf(cnt)) == NULLBUF)
  202.         return NULLBUF;
  203.     wp = cp->data;
  204.     while(cnt != 0 && bp != NULLBUF){
  205.         n = min(cnt,bp->cnt);
  206.         memcpy(wp,bp->data,n);
  207.         wp += n;
  208.         cp->cnt += n;
  209.         cnt -= n;
  210.         bp = bp->next;
  211.     }
  212.     return cp;
  213. }
  214. /* Copy and delete "cnt" bytes from beginning of packet. Return number of
  215.  * bytes actually pulled off
  216.  */
  217. int16
  218. pullup(bph,buf,cnt)
  219. struct mbuf **bph;
  220. char *buf;
  221. int16 cnt;
  222. {
  223.     register struct mbuf *bp;
  224.     int16 n,tot;
  225.  
  226.     tot = 0;
  227.     if(bph == NULLBUFP)
  228.         return 0;
  229.     while(*bph != NULLBUF && cnt != 0){
  230.         bp = *bph;
  231.         n = min(cnt,bp->cnt);
  232.         if(buf != NULLCHAR){
  233.             if(n == 1)    /* Common case optimization */
  234.                 *buf = *bp->data;
  235.             else if(n > 1)
  236.                 memcpy(buf,bp->data,n);
  237.             buf += n;
  238.         }
  239.         tot += n;
  240.         cnt -= n;
  241.         bp->data += n;
  242.         bp->cnt -= n;        
  243.         if(bp->cnt == 0){
  244.             *bph = free_mbuf(bp);
  245.         }
  246.     }
  247.     return tot;
  248. }
  249. /* Append mbuf to end of mbuf chain */
  250. void
  251. append(bph,bp)
  252. struct mbuf **bph;
  253. struct mbuf *bp;
  254. {
  255.     register struct mbuf *p;
  256.  
  257.     if(bph == NULLBUFP || bp == NULLBUF)
  258.         return;
  259.     if(*bph == NULLBUF){
  260.         /* First one on chain */
  261.         *bph = bp;
  262.     } else {
  263.         for(p = *bph ; p->next != NULLBUF ; p = p->next)
  264.             ;
  265.         p->next = bp;
  266.     }
  267. }
  268. /* Insert specified amount of contiguous new space at the beginning of an
  269.  * mbuf chain. If enough space is available in the first mbuf, no new space
  270.  * is allocated. Otherwise a mbuf of the appropriate size is allocated and
  271.  * tacked on the front of the chain.
  272.  *
  273.  * This operation is the logical inverse of pullup(), hence the name.
  274.  */
  275. struct mbuf *
  276. pushdown(bp,size)
  277. register struct mbuf *bp;
  278. int16 size;
  279. {
  280.     register struct mbuf *nbp;
  281.  
  282.     /* Check that bp is real and that there's data space associated with
  283.      * this buffer (i.e., this is not a buffer from dup_p) before
  284.      * checking to see if there's enough space at its front
  285.      */
  286.     if(bp != NULLBUF && bp->size != 0 && bp->data - (char *)(bp+1) >= size){
  287.         /* No need to alloc new mbuf, just adjust this one */
  288.         bp->data -= size;
  289.         bp->cnt += size;
  290.     } else {
  291.         if((nbp = alloc_mbuf(size)) != NULLBUF){
  292.             nbp->next = bp;
  293.             nbp->cnt = size;
  294.             bp = nbp;
  295.         } else {
  296.             bp = NULLBUF;
  297.         }
  298.     }
  299.     return bp;
  300. }
  301. /* Append packet to end of packet queue */
  302. void
  303. enqueue(q,bp)
  304. struct mbuf **q;
  305. struct mbuf *bp;
  306. {
  307.     register struct mbuf *p;
  308.     char i_state;
  309.  
  310.     if(q == NULLBUFP || bp == NULLBUF)
  311.         return;
  312.     i_state = dirps();
  313.     if(*q == NULLBUF){
  314.         /* List is empty, stick at front */
  315.         *q = bp;
  316.     } else {
  317.         for(p = *q ; p->anext != NULLBUF ; p = p->anext)
  318.             ;
  319.         p->anext = bp;
  320.     }
  321.     restore(i_state);
  322.     psignal(q,1);
  323. }
  324. /* Unlink a packet from the head of the queue */
  325. struct mbuf *
  326. dequeue(q)
  327. register struct mbuf **q;
  328. {
  329.     register struct mbuf *bp;
  330.     char i_state;
  331.  
  332.     if(q == NULLBUFP)
  333.         return NULLBUF;
  334.     i_state = dirps();
  335.     if((bp = *q) != NULLBUF){
  336.         *q = bp->anext;
  337.         bp->anext = NULLBUF;
  338.     }
  339.     restore(i_state);
  340.     return bp;
  341. }    
  342.  
  343. /* Copy user data into an mbuf */
  344. struct mbuf *
  345. qdata(data,cnt)
  346. char *data;
  347. int16 cnt;
  348. {
  349.     register struct mbuf *bp;
  350.  
  351.     if((bp = alloc_mbuf(cnt)) == NULLBUF)
  352.         return NULLBUF;
  353.     memcpy(bp->data,data,cnt);
  354.     bp->cnt = cnt;
  355.     return bp;
  356. }
  357. /* Copy mbuf data into user buffer */
  358. int16
  359. dqdata(bp,buf,cnt)
  360. struct mbuf *bp;
  361. char *buf;
  362. unsigned cnt;
  363. {
  364.     unsigned n,tot;
  365.     struct mbuf *bp1;
  366.  
  367.     if(buf == NULLCHAR)
  368.         return 0;
  369.     
  370.     tot = 0;
  371.     for(bp1 = bp;bp1 != NULLBUF; bp1 = bp1->next){
  372.         n = min(bp1->cnt,cnt);
  373.         memcpy(buf,bp1->data,n);
  374.         cnt -= n;
  375.         buf += n;
  376.         tot += n;
  377.     }
  378.     free_p(bp);
  379.     return tot;
  380. }
  381. /* Pull a 32-bit integer in host order from buffer in network byte order */
  382. int32
  383. pull32(bpp)
  384. struct mbuf **bpp;
  385. {
  386.     char buf[4];
  387.  
  388.     if(pullup(bpp,buf,4) != 4){
  389.         /* Return zero if insufficient buffer */
  390.         return 0;
  391.     }
  392.     return get32(buf);
  393. }
  394. /* Pull a 16-bit integer in host order from buffer in network byte order */
  395. int16
  396. pull16(bpp)
  397. struct mbuf **bpp;
  398. {
  399.     char buf[2];
  400.  
  401.     if(pullup(bpp,buf,2) != 2){
  402.         /* Return zero if insufficient buffer */
  403.         return 0;
  404.     }
  405.     return get16(buf);
  406. }
  407. /* Pull single character from mbuf */
  408. char
  409. pullchar(bpp)
  410. struct mbuf **bpp;
  411. {
  412.     char c;
  413.  
  414.     if(pullup(bpp,&c,1) != 1)
  415.         /* Return zero if nothing left */
  416.         c = 0;
  417.     return c;
  418. }
  419. int
  420. write_p(fp,bp)
  421. FILE *fp;
  422. struct mbuf *bp;
  423. {
  424.     while(bp != NULLBUF){
  425.         if(fwrite(bp->data,1,bp->cnt,fp) != bp->cnt)
  426.             return -1;
  427.         bp = bp->next;
  428.     }
  429.     return 0;
  430. }
  431.